import tkinter as tk
import sys
import os
from tkinter import ttk
from PIL import ImageTk, Image

prefix_list = ['0 - 0.0.0.0',
               '1 - 128.0.0.0', '2 - 192.0.0.0', '3 - 224.0.0.0', '4 - 240.0.0.0',
               '5 - 248.0.0.0', '6 - 252.0.0.0', '7 - 254.0.0.0', '8 - 255.0.0.0',
               '9 - 255.128.0.0', '10 - 255.192.0.0', '11 - 255.224.0.0', '12 - 255.240.0.0',
               '13 - 255.248.0.0', '14 - 255.252.0.0', '15 - 255.254.0.0', '16 - 255.255.0.0',
               '17 - 255.255.128.0', '18 - 255.255.192.0', '19 - 255.255.224.0', '20 - 255.255.240.0',
               '21 - 255.255.248.0', '22 - 255.255.252.0', '23 - 255.255.254.0', '24 - 255.255.255.0',
               '25 - 255.255.255.128', '26 - 255.255.255.192', '27 - 255.255.255.224', '28 - 255.255.255.240',
               '29 - 255.255.255.248', '30 - 255.255.255.252', '31 - 255.255.255.254', '32 - 255.255.255.255']
font_big = 24
font_middle = 20
font_small = 18
font_lil = 14


def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)


class Gui(tk.Tk):
    def __init__(self):
        """
        Основная функция для инициализации графического окна
        """
        super().__init__()
        icon = ImageTk.PhotoImage(Image.open(resource_path('ip-network.png')))
        self.iconphoto(False, icon)
        self.title('Калькулятор сетевика')
        self.geometry('400x600')
        self.resizable(False, False)
        self.config(background='#22222e')

        # Определяем стили для элементов интерфейса
        style_tabs = ttk.Style()
        style_tabs.configure('Custom.TNotebook', background='#22222e', )

        style_label = ttk.Style()
        style_label.configure('Custom.TLabel',
                              background='#22222e',
                              foreground='white',
                              font=('PT Sans Narrow', font_small),
                              )
        style_label.configure('Custom_lil.TLabel',
                              background='#22222e',
                              foreground='white',
                              font=('PT Sans Narrow', font_lil),
                              )
        style_entry = ttk.Style()
        style_entry.configure('Custom.TEntry',
                              foreground='white',
                              font=('PT Sans Narrow', font_small, 'bold'),
                              )
        style_entry.map('Custom.TEntry',
                        fieldbackground=[('readonly', '#22222e')],
                        borderwidth=[('readonly', 0)],
                        )
        style_button = ttk.Style()
        style_button.configure('Custom.TButton',
                               background='#4cd964',
                               foreground='white',
                               font=('PT Sans Narrow', font_middle, 'bold'))
        style_button.map('Custom.TButton',
                         foreground=[('pressed', 'white'),
                                     ('active', 'white')],
                         background=[('pressed', '#8e8e93'),
                                     ('active', '#4cd964')],
                         relief=[('pressed', 'flat'),
                                 ('!pressed', 'flat')]
                         )
        style_combobox = ttk.Style()
        style_combobox.configure('Custom1.TCombobox', )
        style_combobox.map(
            'Custom1.TCombobox',
            background=[('readonly', '#8e8e93'), ],
            fieldbackground=[('readonly', '#8e8e93'), ],
            foreground=[('readonly', 'white'), ],
            relief=[('readonly', 'flat'), ],
        )
        style_combobox.configure(
            'Custom2.TCombobox',
            foreground='white',
            fieldbackground='#8e8e93',
            relief='flat',
        )
        style_combobox.map(
            'Custom2.TCombobox',
            fieldbackground=[('active', '#8e8e93'), ],
            foreground=[('active', 'white'), ],
            relief=[('active', 'flat'), ],
        )
        style_spinbox = ttk.Style()
        style_spinbox.configure('Custom.TSpinbox',
                                foreground='white',
                                fieldbackground='#8e8e93',
                                relief='flat',
                                arrowsize=font_lil,
                                )
        style_treeview = ttk.Style()
        style_treeview.configure('Custom.Treeview',
                                 foreground='white',
                                 background='#8e8e93',
                                 fieldbackground='#8e8e93',
                                 relief='flat',
                                 rowheight=25,
                                 font=('PT Sans Narrow', font_lil),
                                 )
        style_treeview.configure('Treeview.Heading',
                                 font=('PT Sans Narrow', font_lil),
                                 )

        # Определяем вкладки
        self.tabControl = ttk.Notebook(self)
        self.tab1 = ttk.Frame(self.tabControl, style='Custom.TNotebook')
        self.tab2 = ttk.Frame(self.tabControl, style='Custom.TNotebook')
        self.tabControl.add(self.tab1, text='Network')
        self.tabControl.add(self.tab2, text='Subnets')

        # Определяем элементы интерфейса
        # Общие для вкладок
        self.label = tk.Label(self,
                              text='LanCalculator',
                              background='#22222e',
                              foreground='white',
                              font=('PT Sans Narrow', font_big, 'bold'),
                              )
        self.entr_ipaddr = tk.Entry(self,
                                    background='#8e8e93',
                                    foreground='white',
                                    font=('PT Sans Narrow', font_middle, 'bold'),
                                    )
        self.prefix_list = prefix_list
        self.entr_prefix_var = tk.StringVar(value=self.prefix_list[24])

        self.entr_prefix = ttk.Combobox(textvariable=self.entr_prefix_var,
                                        values=prefix_list,
                                        style='Custom1.TCombobox',
                                        state='readonly',
                                        font=('PT Sans Narrow', font_middle, 'bold'),
                                        )
        self.button = ttk.Button(self, text='Calculate', style='Custom.TButton')

        # Для вкладки Subnets
        # Для расчета по prefix (первоначально 24'ая маска)
        self.lb_sub_prefix = ttk.Label(
            self.tab2,
            text='subnets prefix',
            style="Custom_lil.TLabel",
        )
        sub_prefix_min = 0
        sub_prefix_max = 32
        self.sub_prefix_cur = tk.StringVar(value='24')
        self.sub_prefix = ttk.Spinbox(self.tab2,
                                      from_=sub_prefix_min,
                                      to=sub_prefix_max,
                                      textvariable=self.sub_prefix_cur,
                                      style='Custom.TSpinbox',
                                      font=('PT Sans Narrow', font_lil),
                                      )
        # для расчета по делителю сети (первоначально расчет из 24'ой маски)
        self.lb_sub_count = ttk.Label(self.tab2,
                                      text='subnets count',
                                      style="Custom_lil.TLabel", )
        self.sub_count_list = [x for x in range(32, 0, -1)]
        self.sub_count_val = [str(2 ** i) for i in range(0, self.sub_count_list.index(24) + 1)]
        self.sub_count_cur = tk.StringVar(value=self.sub_count_val[1])
        self.sub_count = ttk.Combobox(self.tab2,
                                      values=self.sub_count_val,
                                      justify='center',
                                      textvariable=self.sub_count_cur,
                                      style='Custom2.TCombobox',
                                      font=('PT Sans Narrow', font_lil),
                                      )
        # для расчета по числу хостов в сети (первоначально расчет из 24'ой маски)
        self.lb_sub_len = ttk.Label(self.tab2,
                                    text='count of hosts',
                                    style='Custom_lil.TLabel', )
        self.sub_len_val = list(reversed([
            str(1) if i == 0
            else str(2) if i == 1
            else str(2 ** i - 2)
            for i in range(0, 8 + 1)
        ]))
        self.sub_len_cur = tk.StringVar(value=self.sub_len_val[1])
        self.sub_len = ttk.Combobox(self.tab2,
                                    values=self.sub_len_val,
                                    textvariable=self.sub_len_cur,
                                    style='Custom2.TCombobox',
                                    font=('PT Sans Narrow', font_lil),
                                    )
        subnets_tree_columns = ('ip_network', 'first_ip', 'last_ip', 'len_network')
        self.subnets_tree = ttk.Treeview(self.tab2,
                                         columns=subnets_tree_columns,
                                         show='headings',
                                         style='Custom.Treeview',
                                         height=12,
                                         )
        self.subnets_tree.heading('ip_network', text='Сеть', anchor='w')
        self.subnets_tree.heading('first_ip', text='Первый ip', anchor='w')
        self.subnets_tree.heading('last_ip', text='Последний ip', anchor='w')
        self.subnets_tree.heading('len_network', text='Кол-во ip', anchor='w')
        self.subnets_tree.column('#1', stretch=False, width=100)
        self.subnets_tree.column('#2', stretch=False, width=100)
        self.subnets_tree.column('#3', stretch=False, width=100)
        self.subnets_tree.column('#4', stretch=False, width=80)
        self.subnets_tree_scroll = ttk.Scrollbar(
            self.tab2,
            orient='vertical',
            command=self.subnets_tree.yview)
        self.subnets_tree.configure(yscrollcommand=self.subnets_tree_scroll.set)

        # Наименовение параметра
        self.lb_ipaddr = ttk.Label(self.tab1, text='IP address', style="Custom.TLabel", )
        self.lb_netmask = ttk.Label(self.tab1, text='Network mask', style='Custom.TLabel', )
        self.lb_wildcard = ttk.Label(self.tab1, text='Wildcard mask', style='Custom.TLabel', )
        self.lb_ip_network = ttk.Label(self.tab1, text='Network IP address', style='Custom.TLabel', )
        self.lb_ip_broadcast = ttk.Label(self.tab1, text='Broadcast IP address', style='Custom.TLabel', )
        self.lb_len_network = ttk.Label(self.tab1, text='Hosts count', style='Custom.TLabel', )
        self.lb_first_ip = ttk.Label(self.tab1, text='First IP address', style='Custom.TLabel', )
        self.lb_last_ip = ttk.Label(self.tab1, text='Last IP address', style='Custom.TLabel', )

        # Значение параметра
        self.val_ipaddr = ttk.Entry(self.tab1,
                                    font=('PT Sans Narrow', font_small, 'bold'),
                                    state='readonly', style='Custom.TEntry', )
        self.val_netmask = ttk.Entry(self.tab1,
                                     font=('PT Sans Narrow', font_small, 'bold'),
                                     state='readonly',
                                     style='Custom.TEntry',
                                     )
        self.val_wildcard = ttk.Entry(self.tab1,
                                      font=('PT Sans Narrow', font_small, 'bold'),
                                      state='readonly',
                                      style='Custom.TEntry',
                                      )
        self.val_ip_network = ttk.Entry(self.tab1,
                                        font=('PT Sans Narrow', font_small, 'bold'),
                                        state='readonly',
                                        style='Custom.TEntry',
                                        )
        self.val_ip_broadcast = ttk.Entry(self.tab1,
                                          font=('PT Sans Narrow', font_small, 'bold'),
                                          state='readonly',
                                          style='Custom.TEntry',
                                          )
        self.val_len_network = ttk.Entry(self.tab1,
                                         font=('PT Sans Narrow', font_small, 'bold'),
                                         state='readonly',
                                         style='Custom.TEntry',
                                         )
        self.val_first_ip = ttk.Entry(self.tab1,
                                      font=('PT Sans Narrow', font_small, 'bold'),
                                      state='readonly',
                                      style='Custom.TEntry',
                                      )
        self.val_last_ip = ttk.Entry(self.tab1,
                                     font=('PT Sans Narrow', font_small, 'bold'),
                                     state='readonly',
                                     style='Custom.TEntry',
                                     )

        # Определение местоположения элементов интерфейса в графическом окне
        #        self.label.grid(row=0, column=0, columnspan=2, stick='we')
        #        self.entr_ipaddr.grid(row=1, column=0, columnspan=2, stick='we')
        #        self.entr_prefix.grid(row=2, column=0, columnspan=2, stick='we')
        #        self.button.grid(row=3, column=0, columnspan=2, stick='we')
        # Tab1
        self.label.grid(row=0, column=0, stick='we')
        self.entr_ipaddr.grid(row=1, column=0, stick='we')
        self.entr_prefix.grid(row=2, column=0, stick='we')
        self.button.grid(row=3, column=0, stick='we')
        self.lb_ipaddr.grid(row=0, column=0, stick='we')
        self.lb_netmask.grid(row=1, column=0, stick='we')
        self.lb_wildcard.grid(row=2, column=0, stick='we')
        self.lb_ip_network.grid(row=3, column=0, stick='we')
        self.lb_ip_broadcast.grid(row=4, column=0, stick='we')
        self.lb_len_network.grid(row=5, column=0, stick='we')
        self.lb_first_ip.grid(row=6, column=0, stick='we')
        self.lb_last_ip.grid(row=7, column=0, stick='we')
        self.val_ipaddr.grid(row=0, column=1, stick='we')
        self.val_netmask.grid(row=1, column=1, stick='we')
        self.val_wildcard.grid(row=2, column=1, stick='we')
        self.val_ip_network.grid(row=3, column=1, stick='we')
        self.val_ip_broadcast.grid(row=4, column=1, stick='we')
        self.val_len_network.grid(row=5, column=1, stick='we')
        self.val_first_ip.grid(row=6, column=1, stick='we')
        self.val_last_ip.grid(row=7, column=1, stick='we')
        # Tab2
        self.lb_sub_prefix.grid(row=0, column=0, )
        self.lb_sub_count.grid(row=0, column=1, )
        self.lb_sub_len.grid(row=0, column=2, )
        self.sub_prefix.grid(row=1, column=0, stick='we')
        self.sub_count.grid(row=1, column=1, stick='we')
        self.sub_len.grid(row=1, column=2, stick='we')
        self.subnets_tree.grid(row=2, column=0, columnspan=3, stick='we')
        self.subnets_tree_scroll.grid(row=2, column=3, stick='ns')

        self.columnconfigure(0, weight=1, minsize=200)
        for row in range(4):
            self.rowconfigure(row, weight=1, minsize=46)

        for col in range(2):
            self.tab1.columnconfigure(col, weight=1, minsize=200)
        for row in range(8):
            self.tab1.rowconfigure(row, weight=1, minsize=46)

        for col in range(3):
            self.tab2.columnconfigure(col, weight=1, minsize=100)

        self.tabControl.grid()

    def entry_val(self, data):
        """
        Функция для вывода вычесленных параметров
        """
        self.val_normal()
        self.val_delete()
        self.entr_ipaddr.delete(0, tk.END)
        self.entr_ipaddr.insert(0, data['ipaddr'])
        self.val_ipaddr.insert(0, data['ipaddr'])
        self.val_ip_network.insert(0, data['ip_network'])
        self.val_ip_broadcast.insert(0, data['ip_broadcast'])
        self.val_netmask.insert(0, data['netmask'])
        self.val_wildcard.insert(0, data['wildcard'])
        self.val_first_ip.insert(0, data['first_ip'])
        self.val_last_ip.insert(0, data['last_ip'])
        self.val_len_network.insert(0, data['len_network'])
        self.val_readonly()

    def prefix_change(self, prfx):
        """
        Функция для изменения префекса ip сети
        """
        self.entr_prefix_var = tk.StringVar(value=self.prefix_list[prfx])
        self.entr_prefix['state'] = 'normal'
        self.entr_prefix['textvariable'] = self.entr_prefix_var
        self.entr_prefix['state'] = 'readonly'

    def entry_error(self):
        """
        Заполнение при не корректном вводе данных
        """
        self.val_normal()
        self.val_delete()
        self.val_ipaddr.insert(0, 'Нет данных')
        self.val_ip_network.insert(0, 'Нет данных')
        self.val_ip_broadcast.insert(0, 'Нет данных')
        self.val_netmask.insert(0, 'Нет данных')
        self.val_wildcard.insert(0, 'Нет данных')
        self.val_first_ip.insert(0, 'Нет данных')
        self.val_last_ip.insert(0, 'Нет данных')
        self.val_len_network.insert(0, 'Нет данных')
        self.val_readonly()

    def val_normal(self):
        """
        Функция для изменения состояния виджета Entry
        на 'normal', чтобы была возможность изменить значения
        """
        self.val_ipaddr['state'] = 'normal'
        self.val_ip_network['state'] = 'normal'
        self.val_ip_broadcast['state'] = 'normal'
        self.val_netmask['state'] = 'normal'
        self.val_wildcard['state'] = 'normal'
        self.val_first_ip['state'] = 'normal'
        self.val_last_ip['state'] = 'normal'
        self.val_len_network['state'] = 'normal'

    def val_readonly(self):
        """
        Функция для изменения состояния виджета Entry
        на 'readonly'
        """
        self.val_ipaddr['state'] = 'readonly'
        self.val_ip_network['state'] = 'readonly'
        self.val_ip_broadcast['state'] = 'readonly'
        self.val_netmask['state'] = 'readonly'
        self.val_wildcard['state'] = 'readonly'
        self.val_first_ip['state'] = 'readonly'
        self.val_last_ip['state'] = 'readonly'
        self.val_len_network['state'] = 'readonly'

    def val_delete(self):
        """
        Функция очистки параметров
        """
        self.val_ipaddr.delete(0, tk.END)
        self.val_ip_network.delete(0, tk.END)
        self.val_ip_broadcast.delete(0, tk.END)
        self.val_netmask.delete(0, tk.END)
        self.val_wildcard.delete(0, tk.END)
        self.val_first_ip.delete(0, tk.END)
        self.val_last_ip.delete(0, tk.END)
        self.val_len_network.delete(0, tk.END)

    def sub_prefix_change(self, prfx_min):
        """
        Функция для выбора расчетного prefix
        """
        self.sub_prefix_cur.set(str(prfx_min))

    def sub_count_change(self, idx):
        """
        Функция для выбора делителей сети
        """
        self.sub_count_cur.set(self.sub_count_val[idx])

    def sub_len_change(self, idx):
        """
        Функция для выбора числа хостов
        """
        self.sub_len_cur.set(self.sub_len_val[idx])

    def subnets_entry_val(self, subnets_data):
        self.subnets_tree.delete(*self.subnets_tree.get_children())
        for subnet_data in subnets_data:
            self.subnets_tree.insert('', 'end', values=subnet_data)


if __name__ == '__main__':
    ipcalc = Gui()
    ipcalc.mainloop()
